package com.llk.MyThread;

import java.util.ArrayList;
import java.util.List;

/**
 * src.main.java.com.jvonneumann.MyThread.MyThreadPool 类实现了一个简单的线程池。
 * 线程池内部维护一个阻塞队列用于存储任务，
 * 以及一组工作线程用于不断从队列中获取任务并执行。
 *
 * 核心参数包括：
 * - corePoolSize：线程池中始终保持的核心线程数
 * - maximumPoolSize：线程池允许的最大线程数
 * - keepAliveTime：非核心线程在空闲状态下存活的最长时间（单位：毫秒）
 *
 * 线程池支持任务提交（execute）和优雅关闭（shutdown）。
 */
public class MyThreadPool {
    // 核心线程数
    private final int corePoolSize;
    // 最大线程数
    private final int maximumPoolSize;
    // 非核心线程的存活时间（毫秒）
    private final long keepAliveTime;
    // 任务队列
    private final BlockingQueue<Runnable> taskQueue;
    // 保存所有工作线程
    private final List<Worker> workers;
    // 线程池是否已经关闭的标志
    private volatile boolean isShutdown = false;
    // 用于同步控制的锁对象
    private final Object lock = new Object();

    /**
     * 构造方法，根据指定参数初始化线程池。
     *
     * @param corePoolSize   核心线程数
     * @param maximumPoolSize 最大线程数
     * @param keepAliveTime  非核心线程的存活时间（毫秒）
     * @param queueCapacity  任务队列的容量
     */
    public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, int queueCapacity) {
        if (corePoolSize <= 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize) {
            throw new IllegalArgumentException("线程池参数不合法");
        }
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.keepAliveTime = keepAliveTime;
        this.taskQueue = new BlockingQueue<>(queueCapacity);
        this.workers = new ArrayList<>();
    }

    /**
     * execute 方法用于提交任务到线程池。
     * 如果当前工作线程数小于核心线程数，则直接创建新的工作线程来处理任务；
     * 否则将任务放入任务队列中等待执行，如果任务队列中有积压任务且线程数未达到最大值，
     * 则可能创建非核心线程来协同处理任务。
     *
     * @param task 要执行的任务（实现 Runnable 接口）
     * @throws InterruptedException 如果线程在等待过程中被中断
     */
    public void execute(Runnable task) throws InterruptedException {
        if (task == null) {
            throw new IllegalArgumentException("任务不能为空");
        }
        synchronized (lock) {
            if (isShutdown) {
                throw new IllegalStateException("线程池已经关闭，不能提交新任务");
            }
            // 如果当前工作线程数不足核心线程数，则直接启动一个新线程处理任务
            if (workers.size() < corePoolSize) {
                Worker worker = new Worker(task);
                workers.add(worker);
                worker.start();
            } else {
                // 尝试将任务放入任务队列（此处 put 方法会阻塞直到有空位）
                taskQueue.put(task);
                // 如果任务队列中有任务等待且工作线程数尚未达到最大线程数，则扩充线程数量
                if (taskQueue.size() > 0 && workers.size() < maximumPoolSize) {
                    Worker worker = new Worker(null);
                    workers.add(worker);
                    worker.start();
                }
            }
        }
    }

    /**
     * shutdown 方法用于优雅地关闭线程池。
     * 调用该方法后，线程池不再接受新任务，并会等待已提交任务执行完毕后停止所有线程。
     */
    public void shutdown() {
        synchronized (lock) {
            isShutdown = true;
            // 中断所有工作线程
            for (Worker worker : workers) {
                worker.interrupt();
            }
        }
    }

    /**
     * Worker 内部类继承自 Thread，代表线程池中的工作线程。
     * 每个 Worker 在启动后会先执行自身初始化时分配的首个任务，
     * 然后进入一个循环，不断从任务队列中获取任务并执行。
     */
    private class Worker extends Thread {
        // 首个任务，由线程池在创建 Worker 时传入
        private Runnable firstTask;

        /**
         * Worker 构造方法，根据传入的首个任务初始化工作线程。
         *
         * @param firstTask 首个任务，可以为 null，表示先从队列中取任务
         */
        public Worker(Runnable firstTask) {
            this.firstTask = firstTask;
        }

        @Override
        public void run() {
            Runnable task = firstTask;
            // 清空首个任务引用，避免重复执行
            firstTask = null;
            try {
                // 如果任务不为 null 或者从任务队列中获取任务不为空，则执行任务
                while (task != null || (task = taskQueue.take()) != null) {
                    try {
                        task.run();
                    } catch (RuntimeException e) {
                        // 捕获任务执行过程中出现的异常，避免线程因异常退出
                        e.printStackTrace();
                    }
                    task = null;
                    // 非核心线程如果空闲时间超过 keepAliveTime 则退出（简单实现，不做精细计时）
                    if (workers.size() > corePoolSize && isShutdown) {
                        break;
                    }
                }
            } catch (InterruptedException e) {
                // 工作线程被中断后退出
                Thread.currentThread().interrupt();
            } finally {
                // 线程退出前，从工作线程集合中移除自己
                synchronized (lock) {
                    workers.remove(this);
                }
            }
        }
    }
}